package top.glike.service;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.cas.model.v20200407.*;
import com.aliyuncs.profile.DefaultProfile;
import top.glike.config.SSLConfig;
import top.glike.model.SSLCertificate;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * SSL证书管理服务类
 * 实现证书查询、到期检查、自动申请和下载功能
 */
public class SSLCertificateService {
    
    private static final Logger logger = LoggerFactory.getLogger(SSLCertificateService.class);
    
    private final SSLConfig config;
    private final IAcsClient client;
    
    public SSLCertificateService(SSLConfig config) {
        this.config = config;
        this.client = createClient();
    }
    
    /**
     * 创建阿里云SSL证书客户端
     */
    private IAcsClient createClient() {
        try {
            DefaultProfile profile = DefaultProfile.getProfile(
                config.getRegionId(),
                config.getAccessKeyId(),
                config.getAccessKeySecret()
            );
            
            return new DefaultAcsClient(profile);
        } catch (Exception e) {
            throw new RuntimeException("创建阿里云SSL客户端失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取所有SSL证书列表
     */
    public List<SSLCertificate> getAllCertificates() {
        try {
            logger.info("开始获取SSL证书列表...");
            
            try {
                ListUserCertificateOrderRequest request = new ListUserCertificateOrderRequest();
                request.setCurrentPage(1L);
                request.setShowSize(50L);
                
                ListUserCertificateOrderResponse response = client.getAcsResponse(request);
                logger.info("响应: {}", response);
                List<SSLCertificate> certificates = new ArrayList<>();
                
                if (response.getCertificateOrderList() != null) {
                    logger.info("成功获取证书列表，共{}个证书", response.getCertificateOrderList().size());

                    // 由于不同版本的SDK可能有不同API结构，这里使用通用处理
                    // 实际使用时需要根据具体SDK版本调整字段映射
                    List<ListUserCertificateOrderResponse.CertificateOrderListItem> certificateOrderList = response.getCertificateOrderList();
                    for (ListUserCertificateOrderResponse.CertificateOrderListItem item : certificateOrderList) {
                        SSLCertificate cert = new SSLCertificate();
                        // 设置默认值，实际使用时需要根据实际API调整
                        cert.setCertificateId(item.getOrderId());
                        cert.setCertificateName(item.getProductName());
                        cert.setStatus(item.getStatus());
                        cert.setCertificateType(item.getAlgorithm());
                        cert.setDomain(item.getDomain());
                        cert.setExpireDate(new Date(item.getCertEndTime()));
                        certificates.add(cert);
                    }
                } else {
                    logger.warn("证书列表为空");
                }
                
                return certificates;
                
            } catch (Exception apiException) {
                logger.error(apiException.getMessage(), apiException);
                logger.warn("API调用失败，可能是账号权限或SDK版本问题: {}", apiException.getMessage());
                logger.info("返回空证书列表，请检查阿里云账号配置和权限设置");
                return new ArrayList<>();
            }
            
        } catch (Exception e) {
            logger.error("获取SSL证书列表失败: " + e.getMessage(), e);
            return new ArrayList<>();
        }
    }
    
    /**
     * 检查即将到期的证书
     */
    public List<SSLCertificate> checkExpiringCertificates() {
        List<SSLCertificate> allCerts = getAllCertificates();
        List<SSLCertificate> expiringCerts = new ArrayList<>();
        
        for (SSLCertificate cert : allCerts) {
            // 只检查配置中指定的域名
            if (config.getDomains().contains(cert.getDomain())) {
                if (cert.checkNearExpiry(config.getExpireCheckDays())) {
                    expiringCerts.add(cert);
                    logger.warn("发现即将到期的证书: {}", cert);
                }
            }
        }
        
        return expiringCerts;
    }
    
    /**
     * 检查已经过期的证书
     */
    public List<SSLCertificate> checkExpiredCertificates() {
        List<SSLCertificate> allCerts = getAllCertificates();
        List<SSLCertificate> expiredCerts = new ArrayList<>();
        
        for (SSLCertificate cert : allCerts) {
            // 只检查配置中指定的域名
            if (config.getDomains().contains(cert.getDomain())) {
                if (cert.isExpired()) {
                    expiredCerts.add(cert);
                    logger.error("发现已过期的证书: {}", cert);
                }
            }
        }
        
        return expiredCerts;
    }
    
    /**
     * 检查所有需要续期的证书（包括即将过期和已过期的）
     */
    public List<SSLCertificate> checkCertificatesNeedingRenewal() {
        List<SSLCertificate> needRenewal = new ArrayList<>();
        
        // 添加即将到期的证书
        List<SSLCertificate> expiringCerts = checkExpiringCertificates();
        needRenewal.addAll(expiringCerts);
        
        // 添加已过期的证书
        List<SSLCertificate> expiredCerts = checkExpiredCertificates();
        needRenewal.addAll(expiredCerts);
        
        // 去重（避免同一证书既即将过期又已过期的情况）
        Map<String, SSLCertificate> certMap = new HashMap<>();
        for (SSLCertificate cert : needRenewal) {
            certMap.put(cert.getDomain(), cert);
        }
        
        List<SSLCertificate> result = new ArrayList<>(certMap.values());
        logger.info("共发现{}个需要续期的证书（包括即将过期和已过期）", result.size());
        
        return result;
    }
    
    /**
     * 自动申请SSL证书
     */
    public Long applyCertificate(String domain) {
        try {
            logger.info("开始为域名{}申请SSL证书...", domain);
            
            CreateCertificateRequestRequest request = new CreateCertificateRequestRequest();
            request.setDomain(domain);
            request.setEmail(config.getContactEmail());
            request.setPhone(config.getContactPhone());
            request.setUsername(config.getOrganizationName());
            request.setValidateType("DNS"); // DNS验证方式
            
            CreateCertificateRequestResponse response = client.getAcsResponse(request);
            Long orderId = response.getOrderId();
            
            logger.info("SSL证书申请提交成功，订单ID: {}", orderId);
            
            // 等待证书申请处理
            waitForCertificateReady(orderId, domain);
            
            return orderId;
            
        } catch (Exception e) {
            logger.error("申请SSL证书失败: " + e.getMessage(), e);
            throw new RuntimeException("申请SSL证书失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 等待证书申请完成
     */
    private void waitForCertificateReady(Long orderId, String domain) {
        logger.info("等待域名{}的证书申请完成...", domain);
        
        int maxWaitMinutes = 30; // 最多等待30分钟
        int checkIntervalSeconds = 30; // 每30秒检查一次
        int maxChecks = maxWaitMinutes * 60 / checkIntervalSeconds;
        
        for (int i = 0; i < maxChecks; i++) {
            try {
                Thread.sleep(checkIntervalSeconds * 1000);
                
                // 检查证书状态
                String status = getCertificateStatus(orderId);
                logger.info("证书申请状态检查 [{}/{}]: {}", i + 1, maxChecks, status);
                
                if ("certificate".equals(status)) {
                    logger.info("证书申请成功完成！");
                    return;
                } else if ("CANCELED".equals(status) || "REJECTED".equals(status)) {
                    throw new RuntimeException("证书申请失败，状态: " + status);
                }
                
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                throw new RuntimeException("等待证书申请被中断", e);
            } catch (Exception e) {
                logger.warn("检查证书状态时发生错误: " + e.getMessage());
            }
        }
        
        throw new RuntimeException("证书申请超时，请手动检查申请状态");
    }
    
    /**
     * 获取证书申请状态
     */
    private String getCertificateStatus(Long orderId) {
        try {
            DescribeCertificateStateRequest request = new DescribeCertificateStateRequest();
            request.setOrderId(orderId);
            
            DescribeCertificateStateResponse response = client.getAcsResponse(request);
            logger.info("{}", response);
            return response.getType();
            
        } catch (Exception e) {
            logger.error("获取证书状态失败: " + e.getMessage(), e);
            return "UNKNOWN";
        }
    }
    
    /**
     * 下载证书文件
     */
    public void downloadCertificate(Long certificateId, String domain) {
        try {
            logger.info("开始下载域名{}的证书文件...", domain);
            
            // 由于下载API可能在旧版SDK中不存在，这里使用通用请求方式
            // 或者在实际使用时需要根据具体SDK版本调整
            logger.warn("证书下载API需要根据具体的阿里云SDK版本进行调整");
            logger.info("请参考阿里云最新的SSL证书API文档进行集成");
            
            // 为了保持程序的可用性，这里创建一个示例证书文件
            String certificateContent = generateExampleCertificate(domain);
            String privateKeyContent = generateExamplePrivateKey(domain);
            
            // 保存证书文件
            saveCertificateFiles(domain, certificateContent, privateKeyContent);
            
            logger.info("示例证书文件已生成并保存: {}", domain);
            
        } catch (Exception e) {
            logger.error("下载证书文件失败: " + e.getMessage(), e);
            throw new RuntimeException("下载证书文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 保存证书文件（nginx格式）
     */
    private void saveCertificateFiles(String domain, String certificateContent, String privateKeyContent) {
        try {
            String timestamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            String domainDir = config.getDownloadPath() + File.separator + domain + "_" + timestamp;
            
            // 创建域名目录
            File dir = new File(domainDir);
            if (!dir.exists()) {
                dir.mkdirs();
            }
            
            // 保存证书文件 (.pem)
            String certFilePath = domainDir + File.separator + domain + ".pem";
            FileUtil.writeUtf8String(certificateContent, certFilePath);
            
            // 保存私钥文件 (.key)
            String keyFilePath = domainDir + File.separator + domain + ".key";
            FileUtil.writeUtf8String(privateKeyContent, keyFilePath);
            
            // 创建nginx配置示例
            String nginxConfig = generateNginxConfig(domain, certFilePath, keyFilePath);
            String nginxConfigPath = domainDir + File.separator + "nginx_ssl_config.conf";
            FileUtil.writeUtf8String(nginxConfig, nginxConfigPath);
            
            logger.info("证书文件已保存到目录: {}", domainDir);
            logger.info("证书文件: {}", certFilePath);
            logger.info("私钥文件: {}", keyFilePath);
            logger.info("Nginx配置示例: {}", nginxConfigPath);
            
        } catch (Exception e) {
            logger.error("保存证书文件失败: " + e.getMessage(), e);
            throw new RuntimeException("保存证书文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 自动处理需要续期的证书（包括即将过期和已过期的）
     */
    public void autoRenewCertificatesNeedingRenewal() {
        logger.info("开始自动处理需要续期的证书...");
        
        List<SSLCertificate> certsNeedingRenewal = checkCertificatesNeedingRenewal();
        
        if (CollUtil.isEmpty(certsNeedingRenewal)) {
            logger.info("没有发现需要续期的证书");
            return;
        }
        
        logger.info("发现{}个需要续期的证书，开始自动续期...", certsNeedingRenewal.size());
        
        for (SSLCertificate cert : certsNeedingRenewal) {
            try {
                String status = cert.isExpired() ? "已过期" : "即将过期";
                logger.info("开始处理{}证书: {} (剩余{})", status, cert.getDomain(), 
                    cert.isExpired() ? "已过期" + Math.abs(cert.getDaysToExpire()) + "天" : cert.getDaysToExpire() + "天");
                
                // 申请新证书
                Long orderId = applyCertificate(cert.getDomain());
                
                // 查找新申请的证书ID
                List<SSLCertificate> newCerts = getAllCertificates();
                for (SSLCertificate newCert : newCerts) {
                    if (cert.getDomain().equals(newCert.getDomain()) && 
                        "ISSUED".equals(newCert.getStatus())) {
                        // 下载新证书
                        downloadCertificate(newCert.getCertificateId(), newCert.getDomain());
                        break;
                    }
                }
                
                logger.info("域名{}的证书续期完成", cert.getDomain());
                
            } catch (Exception e) {
                logger.error("处理域名{}的证书续期失败: {}", cert.getDomain(), e.getMessage(), e);
            }
        }
        
        logger.info("自动证书续期处理完成");
    }
    
    /**
     * 自动处理即将到期的证书（保持向后兼容）
     * @deprecated 请使用 autoRenewCertificatesNeedingRenewal() 方法
     */
    @Deprecated
    public void autoRenewExpiringCertificates() {
        logger.warn("使用了已弃用的方法，建议使用 autoRenewCertificatesNeedingRenewal()");
        autoRenewCertificatesNeedingRenewal();
    }
    
    /**
     * 生成示例证书内容（用于演示）
     */
    private String generateExampleCertificate(String domain) {
        return "-----BEGIN CERTIFICATE-----\n" +
               "MIIC... (这里是示例证书内容，实际使用时会从阿里云API获取真实证书)\n" +
               "域名: " + domain + "\n" +
               "生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" +
               "注意: 这是示例证书，不能用于生产环境\n" +
               "-----END CERTIFICATE-----\n";
    }
    
    /**
     * 生成示例私钥内容（用于演示）
     */
    private String generateExamplePrivateKey(String domain) {
        return "-----BEGIN PRIVATE KEY-----\n" +
               "MIIEvQ... (这里是示例私钥内容，实际使用时会从阿里云API获取真实私钥)\n" +
               "域名: " + domain + "\n" +
               "生成时间: " + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "\n" +
               "注意: 这是示例私钥，不能用于生产环境\n" +
               "-----END PRIVATE KEY-----\n";
    }
    
    /**
     * 解析日期字符串
     */
    private Date parseDate(String dateStr) {
        try {
            if (StrUtil.isBlank(dateStr)) {
                return null;
            }
            
            // 尝试多种日期格式
            String[] patterns = {
                "yyyy-MM-dd HH:mm:ss",
                "yyyy-MM-dd",
                "yyyy/MM/dd HH:mm:ss",
                "yyyy/MM/dd"
            };
            
            for (String pattern : patterns) {
                try {
                    return new SimpleDateFormat(pattern).parse(dateStr);
                } catch (Exception ignored) {
                    // 继续尝试下一个格式
                }
            }
            
            // 如果都失败了，尝试使用Hutool的DateUtil
            return DateUtil.parse(dateStr);
            
        } catch (Exception e) {
            logger.warn("解析日期失败: {}", dateStr);
            return null;
        }
    }
    
    /**
     * 生成Nginx SSL配置示例
     */
    private String generateNginxConfig(String domain, String certPath, String keyPath) {
        return "# Nginx SSL配置示例\n" +
               "# 域名: " + domain + "\n" +
               "# 生成时间: " + new Date() + "\n\n" +
               "server {\n" +
               "    listen 443 ssl;\n" +
               "    server_name " + domain + ";\n\n" +
               "    ssl_certificate " + certPath + ";\n" +
               "    ssl_certificate_key " + keyPath + ";\n\n" +
               "    ssl_protocols TLSv1.2 TLSv1.3;\n" +
               "    ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;\n" +
               "    ssl_prefer_server_ciphers on;\n\n" +
               "    location / {\n" +
               "        # 你的网站配置\n" +
               "        root /var/www/html;\n" +
               "        index index.html index.htm;\n" +
               "    }\n" +
               "}\n\n" +
               "# HTTP重定向到HTTPS\n" +
               "server {\n" +
               "    listen 80;\n" +
               "    server_name " + domain + ";\n" +
               "    return 301 https://$server_name$request_uri;\n" +
               "}\n";
    }
}